#include "supervision.h"

void supervisor(int nb_children){
  if(nb_children < 1){
    ecrire("At least one child must be created.\n");
    quitter(FAILURE);
  }
  int my_prio = obtenir_priorite(obtenir_pid());
  int child_prio = (my_prio == MAX_PRIORITY?my_prio:my_prio+1);
  //having a supervisor with an higher priority is needed because the child will preempt you otherwise. 
  int i, pid;
  ecrire("Supervisor: let's go !\n");
  for(i = 0; i < nb_children; i++){
    pid = fourchette(child_prio, "supervision_child",NULL);
    if(pid < 0){
      //an error occured
      ecrire("Supervisor: an error occured\n");
      quitter(FAILURE);
    }
    //the child has been successfully spawned
    superviser(pid);
  }
  //now, the supervisor can either do some other stuff or wait for supervision messages. Here, we choose the second option. 
  while(1){
    message_t mess;
    int supervised, status;
    char buf[64];
    char tmp[4];
    //let's filter on the message's priority to ignore all other messages
    if(recevoir_priorite(SUPERVISION_MESSAGE, &mess) == FAILURE){
      quitter(FAILURE);
    }
    //a supervision message has been received. A supervised process has terminated. It is known that it has a process_information payload
    supervised = message_get_from(mess);
    status = message_get_pinfo_status_value(mess);
    strncpy(buf,"Supervisor: the process ",64);
    strncat(buf,itoa(supervised, tmp, 4), 64-strlen(buf));
    strncat(buf," has terminated with status ", 64-strlen(buf));
    strncat(buf, itoa(status, tmp, 4), 64-strlen(buf));
    strncat(buf, "\n", 64-strlen(buf));
    ecrire(buf);
    if(status == 1){
      // the child has exited after 10 messages, restart it
      pid = fourchette(message_get_pinfo_priority_value(mess),obtenir_programme_par_id(message_get_pinfo_program_id_value(mess)), NULL);
      if(pid == OUT_OF_MEMORY)
	//no memory left, our job's done
	break;
      if(pid < 0)
	quitter(FAILURE);
      superviser(pid);
      strncpy(buf,"Process restarted with pid ",64);
      strncat(buf,itoa(pid, tmp, 4), 64-strlen(buf));
      strncat(buf, "\n", 64-strlen(buf));
      ecrire(buf);
    }else if(status == 2)
      // out of memory !
      break;
  }
  ecrire("Supervisor: the system has run out of memory. It is time to leave\n");
  retarder(obtenir_pid(),10000); //let's wait some task for a last child to complete
  quitter(SUCCESS);
}

void supervision_child(){
  int i = 0;
  int pid = obtenir_pid();
  int parent = obtenir_parent(pid);
  char buf[64];
  char tmp[4];
  strncpy(buf, "Child ", 64);
  strncat(buf, itoa(pid,tmp,4), 64-strlen(buf));
  strncat(buf, " started !\n", 64-strlen(buf));
  ecrire(buf);
  while(i < 10){
    // I do two things in my life: sending messages and sleeping
    if(envoyer_entier(parent, 42, 4) == OUT_OF_MEMORY)
      break;
    i ++;
    retarder(pid, 1000);
  }
  strncpy(buf, "Child ", 64);
  strncat(buf, itoa(pid,tmp,4), 64-strlen(buf));
  strncat(buf, " is going to quit !\n", 64-strlen(buf));
  ecrire(buf);
  if(i == 10){
    quitter(1); //ten messages have been sent
  }else
    quitter(2); //out of memory 
}
